const axios = require('axios')
const fs = require('fs')
const LineReader = require('./line-reader')
const path = require('path')
const store = require('./store')
const log = require('./log')

const { execSync } = require('child_process')

function checkClientIdAndSecret() {
    const clientId = store.clientId;
    const clientSecret = store.clientSecret;
    if (!clientId && !clientSecret) {
        throw new Error("missing clientId or secret!")
    }
}

function checkAccessToken(callback) {
    if (store.expired) {
        log.debug("accessToke过期...")
        checkClientIdAndSecret()
        getToken(callback)
        return;
    }
    if (store.accessToken) {
        log.debug("存在accessToken,直接使用...")
        callback()
        return
    }
    checkClientIdAndSecret()
    getToken(callback)

}

function getToken(callback) {
    log.debug("获取access_token...")
    axios.get("https://openapi.data-baker.com/oauth/2.0/token", {
        params: {
            grant_type: "client_credentials",
            client_id: store.clientId,
            client_secret: store.clientSecret
        }
    }).then(response => {
        log.debug(JSON.stringify(response.data))
        if (response.status === 200) {
            store.storeToken(response.data)
            if (callback) {
                callback()
            }
        }
    })
}

function auth(callback) {
    checkAccessToken(() => {
        callback()
    })
}

function ttsFromFile(file, dest) {
    const liner = new LineReader();
    liner.open(file);
    readLineAndTts(liner, dest)
}

function ttsFromF(file,dest) {
    let baseName = path.basename(file)
    const liner = new LineReader();
    liner.open(file);
    const list = []
    readLine(liner,list)
    console.log(JSON.stringify(list))
    ttslist(list,dest,baseName)
}

function readLine(liner,list) {
    if (liner._EOF) {
        return
    }
    var page = {
        statements:[]
    }
    while (true) {
        if (liner._EOF) {
            list.push(page)
            return
        }
        let theline = liner.next();
        console.log('READ LINE: ' + theline);
        if (theline != null && theline.trim()  === '') {
            list.push(page)
            page = {
                statements:[]
            }
            continue
        }
        const obj = matchStr(theline)
        log.debug("voiceName: %s,text: %s", obj.voiceName, obj.text)
        page.statements.push(obj)
    }
}
function readLineAndTts(liner, dest) {
    if (liner._EOF) {
        return
    }
    let theline = liner.next();
    console.log('READ LINE: ' + theline);
    const obj = matchStr(theline)
    log.debug("voiceName: %s,text: %s", obj.voiceName, obj.text)

    tts(obj.text, obj.voiceName, 'ZH', dest, () => {
        readLineAndTts(liner, dest)
    })
}

/**
 * 匹配和获取特定字符
 * @param str
 * @returns {[]}
 */
function matchStr(str) {
    let obj = {}
    if (str) {
        const arrays = str.split(':');
        if (arrays.length > 1) {
            obj.voiceName = arrays[0]
            obj.text = arrays[1]
        } else {
            obj.text = arrays[0]
        }
    }
    return obj
}

function tts(text, voiceName, language, destination, callback) {
    if (!text) {
        callback()
    }
    auth(() => {
        doTts(text, voiceName, language, destination, callback)
    })
}

async function ttslist(list,dest,baseName) {
    for (const index in list) {
        let page = list[index]
        const tempFileList = []
        for (const i in page.statements) {
            let obj = page.statements[i]
            const outFile = await dotts(obj,'ZH',dest)
            tempFileList.push(outFile)
        }
        let pageAudioFileName = path.join(dest, `${baseName}-${index}.mp3`)
        join(tempFileList, pageAudioFileName)
    }
}

async function dotts(obj,language,destination) {
    log.debug("text: %s, voiceName: %s,language: %s,destination: %s", obj.text, obj.voiceName, language, destination)
    const response = await axios.get("https://openapi.data-baker.com/tts", {
        responseType: 'arraybuffer',
        params: {
            voice_name: obj.voiceName != null ? obj.voiceName : 'Lingling',
            text: obj.text,
            language: language != null ? language : 'ZH',
            access_token: store.accessToken,
            domain: 1
        }
    })
    if (response.status !== 200) {
        log.error("status: %s,statusText: %s", response.status, response.statusText)
        throw new Error(`调用接口失败status: ${response.status},statusText: ${response.statusText}`)
    }
    if (response.headers["content-type"] === "application/json") {
        let enc = new TextDecoder('utf-8')
        const obj = JSON.parse(enc.decode(new Uint8Array(response.data))) //转化成json对象
        log.error(obj.err_msg)
        throw new Error(obj.err_msg)
    }
    if (!destination) {
        const dir = process.cwd()
        destination = path.join(dir, 'tts.mp3')
    } else if ("" === path.extname(destination)) {
        const ts = new Date().getTime()
        destination = path.join(destination, `tts-${ts}.mp3`)
    }
    fs.writeFileSync(destination, response.data)
    return destination
}

function doTts(text, voiceName, language, destination, callback) {
    log.debug("text: %s, voiceName: %s,language: %s,destination: %s", text, voiceName, language, destination)
    axios.get("https://openapi.data-baker.com/tts", {
        responseType: 'arraybuffer',
        params: {
            voice_name: voiceName != null ? voiceName : 'Lingling',
            text: text,
            language: language != null ? language : 'ZH',
            access_token: store.accessToken,
            domain: 1
        }
    }).then(response => {
        if (response.status !== 200) {
            log.error("status: %s,statusText: %s", response.status, response.statusText)
            if (callback) {
                callback()
            }
            return
        }
        if (response.headers["content-type"] === "application/json") {
            let enc = new TextDecoder('utf-8')
            const obj = JSON.parse(enc.decode(new Uint8Array(response.data))) //转化成json对象
            log.error(obj.err_msg)
            if (callback) {
                callback(null,obj.err_msg)
            }
            return;
        }
        if (!destination) {
            const dir = process.cwd()
            destination = path.join(dir, 'tts.mp3')
        } else if ("" === path.extname(destination)) {
            const ts = new Date().getTime()
            destination = path.join(destination, `tts-${ts}.mp3`)
        }
        fs.writeFileSync(destination, response.data)
        if (callback) {
            callback(destination)
        }
    })
}

function generateCmd(audioFiles,targetFile) {
    var cmd = 'ffmpeg'
    var fileTargets = ''
    var filter = " -filter_complex '"
    for (const index in audioFiles) {
        fileTargets += ` -i ${audioFiles[index]}`
        filter += `[${index}:0]`
    }
    filter += ` concat=n=${audioFiles.length}:v=0:a=1'`
    const result = cmd + fileTargets + filter + ` ${targetFile}`
    console.log("生成拼接命令: ",result)
    return result
}

function join(audioFiles,targetFile) {
    if (audioFiles.length == 1) {
        execSync(`mv ${audioFiles[0]} ${targetFile}`)
        return
    }
    const cmd = generateCmd(audioFiles,targetFile)
    execSync(cmd)
    for (const index in audioFiles) {
        fs.unlinkSync(audioFiles[index])
    }
}

module.exports = {
    checkClientIdAndSecret,
    tts,
    ttsFromF,
    ttsFromFile
}